﻿using PEAnalyzer.ModeView;
using PEAnalyzer.ModeView.MainPage;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Composition;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;

// https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x804 上介绍了“空白页”项模板

namespace PEAnalyzer
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private MainPageModeView m_pModeView;

        public MainPage()
        {
            this.InitializeComponent();

            m_pModeView = new MainPageModeView();
            DataGrid.DataContext = m_pModeView;
            m_pModeView.SetListChangeCallback(pfnGridViewChanged);

            this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;          
        }

        private async void OnDrop(object sender, DragEventArgs e)
        {
            var fileFromDrop = await e.DataView.GetStorageItemsAsync();
            foreach(IStorageItem file in fileFromDrop)
            {
                var fileInfo = new GridViewItemModeView(file.Name);
                // m_pModeView.FilesInfo.Add(fileInfo);
                AnalyzeFile(file, fileInfo);
                // m_pModeView.FileCount = 0;
            }      
        }

        private void OnDragOver(object sender, DragEventArgs e)
        {
            e.AcceptedOperation = DataPackageOperation.Copy;
        }

        private void NavigateToInfoPage(string strFileName)
        {
            this.Frame.Navigate(typeof(PEInfoPage));
        }

        private async void OnOpenFile(object sender, RoutedEventArgs e)
        {
            FileOpenPicker openPicker = new FileOpenPicker();
            openPicker.ViewMode = PickerViewMode.List;
            openPicker.SuggestedStartLocation = PickerLocationId.Desktop;
            openPicker.FileTypeFilter.Add("*");
            openPicker.FileTypeFilter.Add(".exe");
            openPicker.FileTypeFilter.Add(".dll");
            openPicker.FileTypeFilter.Add(".sys");
            
            var selectFiles = await openPicker.PickMultipleFilesAsync();
            foreach(StorageFile file in selectFiles)
            {
                var fileInfo = new GridViewItemModeView(file.Name);
                // m_pModeView.FilesInfo.Add(fileInfo);
                AnalyzeFile(file, fileInfo);
                // m_pModeView.FileCount = 0;
            }
        }

        private void OnRemoveAllItems(object sender, RoutedEventArgs e)
        {
            m_pModeView.FilesInfo.Clear();
            AnalyzeFileList.ItemsSource = null;
        }

        private void AnalyzeFile(IStorageItem file, GridViewItemModeView pModeView)
        {
            do
            {
                StorageFile pStorageFile = file as StorageFile;
                if(pStorageFile == null)
                {
                    break;
                }

                CoreInterface.PEInfo pPeInfo = null;
                bool bSuccess = false;
                _ = Task.Factory.StartNew(() =>
                {
                    try
                    {
                        pPeInfo = CoreInterface.PEAnalyzer.Analyze(pStorageFile);
                        if (pPeInfo != null)
                        {
                            bSuccess = true;
                        }
                    }
                    catch
                    {

                    }

                    Invoke(() =>
                    {
                        pModeView.PEInfo = pPeInfo;

                        m_pModeView.FilesInfo.Add(pModeView);

                        do
                        {
                            if (bSuccess == false)
                            {
                                pModeView.Status = ANALYZE_STATUS.FAILED;
                            }
                            else
                            {
                                pModeView.Status = ANALYZE_STATUS.SUCCESS;
                            }

                            if (pPeInfo == null)
                            {
                                break;
                            }

                            if (pPeInfo.Get_ImageNtHeader().Get_OptionalHeader().Get_Subsystem() == 1)
                            {
                                pModeView.FileFormat = InfoDef.FILE_FORMAT.SYS;
                            }
                            else if (pPeInfo.Get_ImageNtHeader().Get_OptionalHeader().Get_Subsystem() == 2 ||
                                pPeInfo.Get_ImageNtHeader().Get_OptionalHeader().Get_Subsystem() == 3)
                            {
                                if ((pPeInfo.Get_ImageNtHeader().Get_FileHeader().Get_Characteristics() & 0x2000) == 0x2000)
                                {
                                    pModeView.FileFormat = InfoDef.FILE_FORMAT.DLL;
                                }
                                else
                                {
                                    pModeView.FileFormat = InfoDef.FILE_FORMAT.EXE;
                                }
                            }

                            //分析机器信息
                            string strMachine = CoreInterface.PEAnalyzer.GetMachinInfo(pPeInfo);
                            string strFileAttribute = CoreInterface.PEAnalyzer.GetCharacteristics(pPeInfo);
                            string strSubSystem = CoreInterface.PEAnalyzer.GetSubSystem(pPeInfo);


                            string strMessage = string.Format("运行平台：{0}\r\n区块数目：{1}\r\n文件属性：{2}\r\n子系统：{3}\r\n文件对齐大小：0x{4:X}\r\n内存对齐大小：0x{5:X}",
                                strMachine,
                                pPeInfo.Get_ImageNtHeader().Get_FileHeader().Get_NumberOfSections(),
                                strFileAttribute,
                                strSubSystem,
                                pPeInfo.Get_ImageNtHeader().Get_OptionalHeader().Get_FileAlignment(),
                                pPeInfo.Get_ImageNtHeader().Get_OptionalHeader().Get_SectionAlignment());
                            pModeView.Message = strMessage;
                        } while (false);
                    });
                });

                
            } while (false);
        }

        public async void Invoke(Action action, Windows.UI.Core.CoreDispatcherPriority Priority = Windows.UI.Core.CoreDispatcherPriority.Low)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Priority, () => { action(); });
        }

        private void AnalyzeFileList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            
        }

        private async void AnalyzeFileList_ItemClick(object sender, ItemClickEventArgs e)
        {
            do
            {
                GridViewItemModeView item = e.ClickedItem as GridViewItemModeView;
                if (item == null)
                {
                    break;
                }

                if (item.Status != ANALYZE_STATUS.SUCCESS)
                {
                    if (item.Status == ANALYZE_STATUS.ANALYZING)
                    {
                        ContentDialog noWifiDialog = new ContentDialog()
                        {
                            Title = "提示",
                            Content = "这个文件还没分析完呢，有点慢，再等一会😔",
                            CloseButtonText = "确定"
                        };

                        await noWifiDialog.ShowAsync();
                    }
                    else if(item.Status == ANALYZE_STATUS.FAILED)
                    {
                        ContentDialog noWifiDialog = new ContentDialog()
                        {
                            Title = "提示",
                            Content = "这个文件看起来不是一个PE格式的文件呢😝",
                            CloseButtonText = "确定"
                        };

                        await noWifiDialog.ShowAsync();
                    }

                    break;
                }

                PageParameter pageParameter = new PageParameter();
                pageParameter.PEInfo = item.PEInfo;
                pageParameter.Info = item.Message;
                this.Frame.Navigate(typeof(PEInfoPage), pageParameter, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight});

            } while (false);
        }

        private void OnFindTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
        {
            var suggestList = new List<string>();
            var repeatCheck = new HashSet<string>();
            var keyWord = FindSuggestBox.Text;

            foreach (var item in m_pModeView.FilesInfo)
            {
                if(item.PEInfo == null)
                {
                    continue;
                }

                // 文件名
                var fileName = item.PEInfo.Get_FileName();
                if (fileName.IndexOf(keyWord, StringComparison.CurrentCultureIgnoreCase) >= 0)
                {
                    if(repeatCheck.Add(fileName) == true)
                    {
                        suggestList.Add(fileName);
                    }
                }

                // 模块名 + 导入函数
                var importFunctions = item.PEInfo.Get_ImportFunctionArray();
                foreach (var importItem in importFunctions)
                {
                    var importModuleName = importItem.Get_Name();
                    if (importModuleName.IndexOf(keyWord, StringComparison.CurrentCultureIgnoreCase) >= 0)
                    {
                        if(repeatCheck.Add(importModuleName) == true)
                        {
                            suggestList.Add(importModuleName);
                        }
                        
                    }

                    foreach (var importFunctionItem in importItem.Get_FuncArray())
                    {
                        var importFunctionName = importFunctionItem.Get_Name();
                        if (importFunctionName.IndexOf(keyWord, StringComparison.CurrentCultureIgnoreCase) >= 0)
                        {
                            if(repeatCheck.Add(importFunctionName) == true)
                            {
                                suggestList.Add(importFunctionName);
                            }
                        }
                    }
                }

                // 导出函数
                var exportFunction = item.PEInfo.Get_ExportFunction();
                foreach (var exportItem in exportFunction.Get_FunctionArray())
                {
                    var exportFunctionName = exportItem.Get_Name();
                    if (exportFunctionName.IndexOf(keyWord, StringComparison.CurrentCultureIgnoreCase) >= 0)
                    {
                        if(repeatCheck.Add(exportFunctionName) == true)
                        {
                            suggestList.Add(exportFunctionName);
                        }
                    }
                }
            }

            FindSuggestBox.ItemsSource = suggestList;
        }

        private void OnFindSuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)
        {
            m_pModeView.SetFilter(0, args.SelectedItem.ToString());
            AnalyzeFileList.ItemsSource = m_pModeView.FilesInfo;
        }

        private void OnFingSubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
        {
            m_pModeView.SetFilter(0, args.QueryText);
            AnalyzeFileList.ItemsSource = m_pModeView.FilesInfo;
        }

        private void pfnGridViewChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            AnalyzeFileList.ItemsSource = m_pModeView.FilesInfo;
            m_pModeView.PECount = 0;
        }

        private void OnShowAboutPage(object sender, RoutedEventArgs e)
        {
            this.Frame.Navigate(typeof(AboutPage), null, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
        }
    }
}
